﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using TasksDataXml.Exceptions;

namespace TasksDataXml.Data
{
    public class Category : BaseDataItem
    {
        private List<Category> _categoryList = new List<Category>();
        private List<string> _taskPathList = new List<string>();
        private List<Task> _tasks = new List<Task>();

        [XmlAttribute("Name")]
        public string Name { get; set; }
        [XmlAttribute("Id")]
        public string Id
        {
            get { return GuidId.ToString(); }
            set
            {
                Guid g;
                if(Guid.TryParse(value, out g))
                {
                    GuidId = g;
                }
            }
        }

        [XmlIgnore]
        public Guid GuidId { get; set; }

        [XmlElement("Category")]
        public List<Category> CategoryList
        {
            get { return _categoryList; }
            set { _categoryList = value; }
        }

        [XmlArrayItem("Task", typeof(string))]
        [XmlArray("Tasks")]
        public List<string> TaskPathList
        {
            get { return _taskPathList; }
            set { _taskPathList = value; }
        }

        [XmlIgnore]
        public List<Task> Tasks
        {
            get { return _tasks; }
            set { _tasks = value; }
        }

        [XmlIgnore]
        public override string Folder
        {
            get { return Id; }
        }

        [XmlIgnore]
        public override string Filename
        {
            get { return string.Empty; }
        }

        public override IBaseDataItem RemoveItem(IBaseDataItem item)
        {
            item.NotifyParentAdd = null;
            item.NotifyParentMove = null;

            var c = item as Category;
            if (c != null)
            {
                _categoryList.Remove(c);
                return null;
            }

            var t = item as Task;
            if (t != null)
            {
                RemoveTask(t);
                return null;
            }

            return null;
        }

        public void LoadTasks(DataSerializer<Task> serializer, string root, List<CommonException> excList)
        {
            try
            {
                var tasksFolder = GetFullPath(root);
                var taskNames = new List<string>(TaskPathList);
                foreach (var path in taskNames)
                {
                    var file = Path.Combine(tasksFolder, path);
                    CommonException ex;
                    LoadTask(file, serializer, out ex);
                    if (ex != null)
                    {
                        excList.Add(ex);
                        TaskPathList.Remove(path);
                    }
                }

                root = GetFolder(root);
                if(CategoryList.Count > 0)
                {
                    foreach (var category in CategoryList)
                    {
                        category.LoadTasks(serializer, root, excList);
                    }
                }
            }
            catch (Exception eex)
            {
                excList.Add(new CommonException("Load tasks exception", eex));
            }
        }

        public void SaveTasks(DataSerializer<Task> serializer, string root, List<CommonException> excList)
        {
            if(serializer == null)
            {
                excList.Add(new CommonException("Tasks serializer is null"));
                return;
            }

            if(string.IsNullOrEmpty(root))
            {
                excList.Add(new CommonException("Tasks foleder is null"));
                return;
            }

            if(!Directory.Exists(root))
            {
                excList.Add(new CommonException("Tasks foleder doesn't exist"));
                return;
            }

            TaskPathList.Clear();

            var saveFolder = GetFolder(root);

            foreach (var task in Tasks)
            {
                var saveName = Path.Combine(saveFolder, task.Filename);
                CommonException ex;
                serializer.WriteFile(saveName, task, out ex);
                if (ex != null)
                {
                    excList.Add(ex);
                }
                else
                {
                    TaskPathList.Add(task.Filename);
                }
            }

            foreach (var category in CategoryList)
            {
                category.SaveTasks(serializer, saveFolder, excList);
            }
        }

        private void LoadTask(string path, DataSerializer<Task> serializer, out CommonException ex)
        {
            var task = serializer.ReadFile(path, out ex);
            if (task != null)
                AddTask(task);
        }

        public void AddCategory(Category category)
        {
            category.NotifyParentMove = RemoveItem;
            CategoryList.Add(category);
        }

        public void MoveCategory(Category target)
        {
            if (NotifyParentMove != null)
                NotifyParentMove(this);

            target.AddCategory(this);
        }

        public void AddTask(Task data)
        {
            data.NotifyParentMove = RemoveItem;
            Tasks.Add(data);
        }

        private void RemoveTask(Task data)
        {
            if(data != null)
            {
                data.NotifyParentMove = null;
                Tasks.Remove(data);
            }
        }

        internal void DeleteTask(Task data)
        {
            RemoveTask(data);
            data.Dispose();
        }

        internal void DeleteAllTasks()
        {
            foreach (var task in Tasks)
            {
                DeleteTask(task);
            }
        }

        internal void DeleteMe()
        {
            NotifyParentAdd = null;
            NotifyParentMove = null;

            DeleteAllTasks();
            foreach (var category in CategoryList)
            {
                category.DeleteMe();
            }
        }

        public override void AttachCallbacks(IBaseDataItem parentCategory)
        {
            if(parentCategory != null)
            {
                parentCategory.NotifyParentMove = RemoveItem;
            }

            foreach (var category in CategoryList)
            {
                category.AttachCallbacks(this);
            }
        }

        public override void Dispose()
        {
            DeleteMe();
            base.Dispose();
        }
    }
}
